package com.zhen.generator.ui;

import java.awt.EventQueue;
import java.awt.Font;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.sql.Connection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JSeparator;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
import javax.swing.UIManager;
import javax.swing.text.JTextComponent;

import org.apache.commons.lang3.StringUtils;
//import org.jb2011.lnf.beautyeye.BeautyEyeLNFHelper;
//import org.jb2011.lnf.beautyeye.ch3_button.BEButtonUI;

import com.zhen.generator.Configuration;
import com.zhen.generator.DatabaseInfoOp;
import com.zhen.generator.enums.DBTypeEnum;
import com.zhen.generator.util.FileHelper;

import cn.org.rapid_framework.generator.GeneratorConstants;
import cn.org.rapid_framework.generator.GeneratorFacade;
import cn.org.rapid_framework.generator.util.GLogger;
import cn.org.rapid_framework.generator.util.SystemHelper;

/**
 * 通过UI操作代码生成器。
 * 
 * @author Luffy
 *
 */
public class GeneratorFrame extends JFrame {
    private static final long serialVersionUID = -937060812524683010L;

    /**
     * 标签组件默认宽度
     */
    private static final int LABEL_WIDTH = 90;

    /**
     * 标签组件默认高度度
     */
    private static final int LABEL_HEIGHT = 15;

    /**
     * 文本编辑组件默认宽度
     */
    private static final int TEXTFIELD_WIDTH = 250;

    /**
     * 文本编辑组件默认高度度
     */
    private static final int TEXTFIELD_HEIGHT = 25;

    /**
     * UIManager中UI字体相关的key
     */
    public static String[] DEFAULT_FONT = new String[] {
        "Table.font", "TableHeader.font", "CheckBox.font", "Tree.font",
        "Viewport.font", "ProgressBar.font", "RadioButtonMenuItem.font",
        "ToolBar.font", "ColorChooser.font", "ToggleButton.font", "Panel.font",
        "TextArea.font", "Menu.font", "TableHeader.font", "TextField.font",
        "OptionPane.font", "MenuBar.font", "Button.font", "Label.font",
        "PasswordField.font", "ScrollPane.font", "MenuItem.font",
        "ToolTip.font", "List.font", "EditorPane.font", "Table.font",
        "TabbedPane.font", "RadioButton.font", "CheckBoxMenuItem.font",
        "TextPane.font", "PopupMenu.font", "TitledBorder.font", "ComboBox.font"
    };

    /**
     * 数据库驱动器数组
     */
    private final String[] drivers = DBTypeEnum.getDBDrivers();

    private final Object[] options = {
        " 确定 ", " 取消 "
    };

    /**
     * 缓存组件，方便获取
     */
    private final Map<JLabel, JTextComponent> cache = new HashMap<JLabel, JTextComponent>();

    private JPanel contentPane;

    private JComboBox<?> comboBox_driver;

    private JCheckBox checkBox_rebuild;

    /**
     * Create the frame.
     */
    public GeneratorFrame() {
        init();
    }

    /**
     * Launch the application.
     */
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
//                    BeautyEyeLNFHelper.launchBeautyEyeLNF();
                    UIManager.put("RootPane.setupButtonVisible", false);
                    // 设置本属性将改变窗口边框样式定义
//                    BeautyEyeLNFHelper.frameBorderStyle = BeautyEyeLNFHelper.FrameBorderStyle.osLookAndFeelDecorated;
//                    BeautyEyeLNFHelper.launchBeautyEyeLNF();
                    // 调整默认字体
                    for (int i = 0; i < DEFAULT_FONT.length; i++) {
                        UIManager.put(DEFAULT_FONT[i],
                                new Font("微软雅黑", Font.PLAIN, 13));
                    }
                    GeneratorFrame frame = new GeneratorFrame();
                    frame.setVisible(true);
                }
                catch (Exception e) {
                    GLogger.error(e.getMessage(), e);
                }
            }
        });
    }

    /**
     * 初始化布局。
     */
    void init() {
        // ----------------主面板框----------------
        this.setTitle("珍品网代码生成器");
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setBounds(100, 100, 800, 490);
        contentPane = new JPanel();
        contentPane.setBorder(BorderFactory.createEtchedBorder());
        contentPane.setLayout(null);
        this.setContentPane(contentPane);

        // ----------------数据源面板----------------
        JPanel dataSourcePanel = new JPanel();
        dataSourcePanel.setBounds(20, 10, 760, 150);
        dataSourcePanel.setLayout(null);
        dataSourcePanel.setBorder(BorderFactory.createTitledBorder("数据源"));
        contentPane.add(dataSourcePanel);

        // 数据库驱动
        this.addComboBoxItem(dataSourcePanel, Configuration.DRIVER, "数据库驱动：",
                drivers, 10, 35);
        // 数据库URL
        this.addTextItem(dataSourcePanel, Configuration.URL, "数据库URL：",
                "jdbc:mysql://192.168.1.102/zyems?useUnicode=true&amp;characterEncoding=UTF-8",
                370, 35);
        // 用户名
        this.addTextItem(dataSourcePanel, Configuration.USERNAME, "用户名：",
                "root", 10, 75);
        // 密码
        this.addTextItem(dataSourcePanel, Configuration.PASSWORD, "密码：",
                "123", 370, 75);
        // 按钮：测试连接
        JButton btn_test = new JButton("测试连接");
        //btn_test.setUI(
            //    new BEButtonUI().setNormalColor(BEButtonUI.NormalColor.green));
        btn_test.addActionListener(new ConnectActionListener());
        btn_test.setBounds(625, 115, 95, 25);
        dataSourcePanel.add(btn_test);

        // ----------------参数设置面板----------------
        JPanel propertyPanel = new JPanel();
        propertyPanel.setBounds(20, 170, 760, 240);
        propertyPanel.setLayout(null);
        propertyPanel.setBorder(BorderFactory.createTitledBorder("参数设置"));
        contentPane.add(propertyPanel);

        // 生成包前缀
        this.addTextItem(propertyPanel, Configuration.BASEPACKAGE, "生成包前缀：",
                "com.zy", 10, 35);
        // 生成代码输出目录，默认当前目录
        this.addTextItem(propertyPanel, Configuration.OUTROOT, "输出目录：",
                FileHelper.getCurrentPath(), 10, 75);
        // 表名
        this.addTextItem(propertyPanel, Configuration.TABLENAME, "表名：", "*", 10,
                115);
        // 数据库表前缀
        this.addTextItem(propertyPanel, Configuration.TABLEREMOVEPREFIXES,
                "数据表前缀：", "", 10, 155);

        checkBox_rebuild = new JCheckBox("重新生成");
        JPanel boxPanel = new JPanel();
        boxPanel.setBounds(100, 185, 90, 35);
        boxPanel.add(checkBox_rebuild);
        propertyPanel.add(boxPanel);

        JButton btn_gener = new JButton("生成代码");
        /*btn_gener.setUI(
                new BEButtonUI().setNormalColor(BEButtonUI.NormalColor.blue));*/
        btn_gener.addActionListener(new GenerateActionListener());
        btn_gener.setBounds(650, 415, 95, 25);
        contentPane.add(btn_gener);

        this.setResizable(false);
        this.setLocationRelativeTo(null);

        // addSeparator(JSeparator.HORIZONTAL, new Rectangle(10, 270, 350, 2));
    }

    /**
     * 添加下拉列表项，包含标签和下拉列表框。
     * 
     * @param panel
     * @param field
     * @param label
     * @param items
     * @param x
     * @param y
     */
    private <T> void addComboBoxItem(JPanel panel, String field, String label,
            T[] items, int x, int y) {
        // 标签
        this.addLabel(panel, field, label,
                new Rectangle(x, y, LABEL_WIDTH, LABEL_HEIGHT));
        // 下拉列表框
        comboBox_driver = new JComboBox<T>(items);
        comboBox_driver.setBounds(x + 100, y - 5, TEXTFIELD_WIDTH,
                TEXTFIELD_HEIGHT);
        panel.add(comboBox_driver);
    }

    /**
     * 添加文本编辑项，包含标签和文本编辑框。
     * 
     * @param panel
     * @param field
     * @param label
     * @param text
     * @param x
     * @param y
     */
    private void addTextItem(JPanel panel, String field, String label,
            String text, int x, int y) {
        // 标签
        JLabel jlabel = this.addLabel(panel, field, label,
                new Rectangle(x, y, LABEL_WIDTH, LABEL_HEIGHT));
        // 文本编辑框
        JTextField textField = this.addTextField(panel, text, new Rectangle(
                x + 100, y - 5, TEXTFIELD_WIDTH, TEXTFIELD_HEIGHT));
        // 缓存组件
        this.cache.put(jlabel, textField);
    }

    /**
     * 添加标签元素项。
     * 
     * @param panel
     * @param field
     * @param text
     * @param r
     * @return
     */
    private JLabel addLabel(JPanel panel, String field, String text,
            Rectangle r) {
        JLabel label = new JLabel(text);
        // 将属性字段记录到名称中
        label.setName(field);
        label.setVerticalAlignment(SwingConstants.BOTTOM);
        label.setHorizontalAlignment(SwingConstants.RIGHT);
        label.setBounds(r.x, r.y, r.width, r.height);
        panel.add(label);
        return label;
    }

    /**
     * 添加文本编辑项。
     * 
     * @param panel
     * @param text
     * @param r
     * @return
     */
    private JTextField addTextField(JPanel panel, String text, Rectangle r) {
        JTextField textField = new JTextField();
        textField.setText(text);
        textField.setColumns(10);
        textField.setBounds(r.x, r.y, r.width, r.height);
        panel.add(textField);
        return textField;
    }

    /**
     * 添加水平或垂直分割线。
     * 
     * @param orientation (JSeparator.HORIZONTAL, JSeparator.VERTICAL)
     * @param r
     */
    protected void addSeparator(int orientation, Rectangle r) {
        JSeparator separator = new JSeparator(orientation);
        separator.setBounds(r.x, r.y, r.width, r.height);
        contentPane.add(separator);
    }

    /**
     * 获取指定字段的文本内容。
     * 
     * @param field
     * @return
     */
    private String getFieldValue(String field) {
        for (Entry<JLabel, JTextComponent> entry : cache.entrySet()) {
            JLabel label = entry.getKey();
            JTextComponent textComp = entry.getValue();
            if (field != null && field.equalsIgnoreCase(label.getName())) {
                return textComp.getText();
            }
        }
        return null;
    }

    /**
     * 验证是否为空
     * 
     * @return
     */
    private boolean validation() {
        List<String> nonFields = Configuration.getNonFields();
        for (Entry<JLabel, JTextComponent> entry : cache.entrySet()) {
            JLabel label = entry.getKey();
            JTextComponent textComp = entry.getValue();
            if (nonFields.contains(label.getName()) && this.isEmpty(textComp)) {
                MessageDialog.showWarning(label.getText() + "不能为空！");
                textComp.requestFocus();
                return false;
            }
        }
        return true;
    }

    /**
     * 判断输入框是否为空
     * 
     * @param component
     * @return
     */
    private boolean isEmpty(JTextComponent component) {
        if (component == null) {
            return true;
        }
        String content = component.getText();
        return null == content || content.equals("");
    }

    /**
     * 测试数据库连接。
     * 
     * @author Luffy
     *
     */
    class ConnectActionListener implements ActionListener {

        public void actionPerformed(ActionEvent e) {
            // 输入内容校验
            if (!validation()) {
                return;
            }
            String classDriver = (String) comboBox_driver.getSelectedItem();
            String url = getFieldValue(Configuration.URL);
            String username = getFieldValue(Configuration.USERNAME);
            String password = getFieldValue(Configuration.PASSWORD);
            Connection conn = new DatabaseInfoOp(classDriver, url, username,
                    password).getConnectionByJDBC();
            if (null != conn) {
                MessageDialog.showInfo("连接成功！");
            }
            else {
                MessageDialog.showError("数据库连接失败，请检查后重试！");
            }
        }
    }

    /**
     * 生成代码操作。
     * 
     * @author Luffy
     *
     */
    class GenerateActionListener implements ActionListener {

        public void actionPerformed(ActionEvent e) {
            // 输入内容校验
            if (!validation()) {
                return;
            }
            String classDriver = (String) comboBox_driver.getSelectedItem();
            String url = getFieldValue(Configuration.URL);
            String username = getFieldValue(Configuration.USERNAME);
            String password = getFieldValue(Configuration.PASSWORD);
            String basepkg = getFieldValue(Configuration.BASEPACKAGE);
            // 输出目录
            String outRoot = getFieldValue(Configuration.OUTROOT);
            if (StringUtils.isBlank(outRoot)) {
                // 未指定目录时默认取当前目录
                outRoot = FileHelper.getCurrentPath();
            }

            String prefixes = getFieldValue(Configuration.TABLEREMOVEPREFIXES);

            Configuration.setProperty(GeneratorConstants.JDBC_DRIVER,
                    classDriver);
            Configuration.setProperty(GeneratorConstants.JDBC_URL, url);
            Configuration.setProperty(GeneratorConstants.JDBC_USERNAME,
                    username);
            Configuration.setProperty(GeneratorConstants.JDBC_PASSWORD,
                    password);
            Configuration.setProperty(GeneratorConstants.TABLE_REMOVE_PREFIXES,
                    prefixes);
            Configuration.setProperty(Configuration.BASEPACKAGE, basepkg);
            Configuration.setProperty(Configuration.OUTROOT, StringUtils
                    .stripEnd(outRoot, File.separator).concat(File.separator + "generator-output"));

            // 数据库表名
            String tableNames = getFieldValue(Configuration.TABLENAME);

            boolean flag = generate(tableNames);
            if (flag) {
                int response = JOptionPane.showOptionDialog(GeneratorFrame.this,
                        "代码已经生成，是否打开输出目录？", "确认", JOptionPane.OK_OPTION,
                        JOptionPane.QUESTION_MESSAGE, null, options,
                        options[0]);
                // 打开文件夹
                if (response == 0 && SystemHelper.isWindowsOS) {
                    try {
                        Runtime.getRuntime().exec("cmd.exe /c start "
                                + outRoot.replace('/', '\\'));
                    }
                    catch (IOException e1) {
                        MessageDialog.showError("打开文件夹失败，请检查后重试！");
                    }
                }
            }
        }

        /**
         * 执行生成任务。
         */
        private boolean generate(String tableNames) {
            try {
                String[] tables = StringUtils.split(tableNames, ",");

                GeneratorFacade g = new GeneratorFacade();
                // 添加模板的位置
                g.getGenerator().addTemplateRootDir("classpath:template");

                // 打印数据库中的表名称
                // GeneratorFacade.printAllTableNames();

                // 删除生成器的输出目录
                if (checkBox_rebuild.isSelected()) {
                    g.deleteOutRootDir();
                }

                // 通过数据库表生成文件
                g.generateByTable(tables);

                // 自动搜索数据库中的所有表并生成文件
                // g.generateByAllTable();

                // 删除生成的文件
                // g.deleteByTable("table_name");

                // 删除所有生成的文件
                // g.deleteByAllTable();
            }
            catch (Exception e) {
                MessageDialog.showError(e.getMessage());
                return false;
            }
            return true;
        }
    }

}
